/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  Rand.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2016/08/20
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#include "Rand.h"
#include "gbkmap.h"
#include <vector>
#include <QDateTime>

namespace qb{
	namespace base{
		class RandImpl{
			BaseString			m_alphabet;
			BaseString			m_numbers;
			BaseString			m_cnstring;
			BaseString			m_keystring;
		public:
			RandImpl()
			{
                qb::base::CGbkMap gbkmap;
				m_numbers = "0123456789";
				m_keystring = "~!@#$%^&*()_+{}:\"|<>?`-=[];'\\,./";
				m_alphabet  = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
                m_cnstring = gbkmap.GetAreaString(qb::base::kGbkHanziTypeGbk2).c_str();
			}
			static RandImpl& Get()
			{
				static RandImpl impl;
				return impl;
			}
			int RandInt(int mi, int mx)
			{
				//static boost::random::mt19937 rng;
				//static boost::uniform_int<> ui;
				//return mi + ui(rng)% (mx - mi);
				static int seed = 0x5412437;
				if (mx == mi)
					return mi;
				if (mi > mx)std::swap(mi, mx);

                uint32_t dt = QDateTime::currentMSecsSinceEpoch();
                srand(seed+dt);
				srand(seed);
				int last = rand();
                seed += last + dt;
				return mi + (last) % (mx - mi);
			}
			void RandString(BaseString& out, int minLength, int maxLength, DWORD flag)
			{
				if (flag&RSF_BASE64)
				{
					flag = RSF_Alphabet | RSF_Number;
				}
				int nselect = 0;
				DWORD flags[5] = { 0 };
				if (flag&RSF_Alphabet){ flags[nselect++] = RSF_Alphabet; }
				if (flag&RSF_Number){ flags[nselect++] = RSF_Number; }
				if (flag&RSF_CNWord){ flags[nselect++] = RSF_CNWord; }
				if (flag&RSF_Keyboard){ flags[nselect++] = RSF_Keyboard; }
				if (flag&RSF_CAPITAL){ flags[nselect++] = RSF_CAPITAL; }
				int len = RandInt(minLength, maxLength);
				out.expand(len);
				out.clear();
				for (int i = 0; i < len ; i++)
				{
					int select = nselect > 1 ? RandInt(0, nselect) : 0;
					switch (flags[select])
					{
					case RSF_Alphabet:out.push_back(m_alphabet[RandInt(0, m_alphabet.size())]); break;
					case RSF_CAPITAL:out.push_back(m_alphabet[RandInt(m_alphabet.size()/2, m_alphabet.size())]); break;
					case RSF_Number:out.push_back(m_numbers[RandInt(0, m_numbers.size())]); break;
					case RSF_CNWord:
					{
						int pos = RandInt(0, m_cnstring.size()/2);
						out.push_back(m_cnstring[pos*2]);
						out.push_back(m_cnstring[pos*2+1]);
						i++;
					}
					break;
					case RSF_Keyboard:out.push_back(m_keystring[RandInt(0, m_keystring.size())]); break;
					}
				}
			}
		};
		namespace{
			static double resmaxd = 1.0 / RAND_MAX;
			static float  resmax = 1.0f / RAND_MAX;
		}
		class NumGeneratorImpl{
			class Node{
				bool	m_must;
			public:
				Node() :m_must(true){}
				virtual ~Node(){}
				bool IsMust()const{ return m_must; }
				void SetMust(bool must){ m_must = must; }
				virtual void Build(std::string& str){}
			};
			class Meta : public Node{//本身最多选取mx,最少选取mi
				int			m_min, m_max;
				std::string	m_chars;
			public:
				Meta(const char* str, int mi, int mx) :m_min(mi), m_max(mx)
				{
					int len = strlen(str);
					for (int i = 0; i < len; i++)
					{
						if (i + 2 < len && str[i + 1] == '-')//处理连字符,如0-9,a-zA-Z
						{
							for (char c = str[i]; c <= str[i + 2]; c++){ m_chars.push_back(c); }
							i += 2;
						}
						else
							m_chars.push_back(str[i]);
					}
				}
				virtual ~Meta(){}
				virtual void Build(std::string& str)
				{
                    int ncount = qb::base::Rand::RandInt(m_min, m_max);
					for (int i = 0; i < ncount; i++)
					{
                        int isel = qb::base::Rand::RandInt(0, m_chars.size());
						str.push_back(m_chars[isel]);
					}
				}
			};
			class MetaLine : public Node{//每个节点都必选
				struct NodeInfo{
					Node*	node;
					int		mi, mx;
				};
                std::vector<Node*>	m_steps;
			public:
				MetaLine(){}
				virtual ~MetaLine(){
					for (int i = 0; i < (int)m_steps.size(); i++){ delete m_steps[i]; }
				}
				MetaLine(const std::initializer_list<Node*>& nodes){
					m_steps.assign(nodes.begin(), nodes.end());
					for (auto it = m_steps.begin(); it != m_steps.end(); ++it)(*it)->SetMust(true);
				}
				void AddNode(Node* child, bool must){
					child->SetMust(must);
					m_steps.push_back(child);
				}
				virtual void Build(std::string& str)
				{
					for (int i = 0; i < (int)m_steps.size(); i++)
					{
						Node* sub = m_steps[i];
                        if (sub->IsMust() || qb::base::Rand::RandInt(0, 100) % 2 == 0)
							sub->Build(str);
					}
				}
			};
			class MetaSelect : public Node{//在多个MetaLine之间选取一个
                std::vector<MetaLine*>	m_lines;
			public:
				MetaSelect(const std::initializer_list<MetaLine*>& lines){
					m_lines.assign(lines.begin(), lines.end());
				}
				virtual ~MetaSelect(){
					for (int i = 0; i < (int)m_lines.size(); i++){ delete m_lines[i]; }
				}
				virtual void Build(std::string& str)
				{
                    int select = qb::base::Rand::RandInt(0, m_lines.size());
					if (select >= 0 && select < (int)m_lines.size())
						m_lines[select]->Build(str);
				}
			};
			MetaLine*	m_root;
			int			m_int_count;	// 最大整数长度
			int			m_digit_count;	// 最大小数长度
			int			m_exp_count;	// 最大指数长度
		public:
			NumGeneratorImpl() :m_int_count(12), m_digit_count(6), m_exp_count(2), m_root(nullptr){}
			~NumGeneratorImpl(){
				if (m_root)delete m_root;
			}
			void SetIntPartCount(unsigned int count){ m_int_count = count; }
			void SetDigitPartCount(unsigned int count){ m_digit_count = count; }
			void SetExpPartCount(unsigned int count){ m_exp_count = count; }
			std::string Build()
			{
				Init();
				std::string str;
				if (m_root == nullptr)return str;
				m_root->Build(str);
				return str;
			}
		protected:
			void Init(){
				if (m_root)return;
				// 正则表达式:"[+-]?(\\d+(\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?"
				MetaLine* m1 = new MetaLine();
				m1->AddNode(new Meta("0-9", 1, m_int_count), true);
				m1->AddNode(new MetaLine({ new Meta(".", 1, 1), new Meta("0-9", 0, m_digit_count) }), false);
				MetaLine* m2 = new MetaLine({
					new Meta(".", 1, 1),
					new Meta("0-9", 1, m_digit_count)
				});
				MetaLine* m3 = new MetaLine({
					new Meta("eE", 1, 1),
					new Meta("+-", 0, 1),
					new Meta("0-9", 1, m_exp_count)
				});
				MetaLine* root = new MetaLine();
				root->AddNode(new Meta("+-", 0, 1), true);
				root->AddNode(new MetaSelect({ m1, m2 }), true);
				root->AddNode(m3, false);
				m_root = root;
			}
		};

		int Rand::RandInt(int mi, int mx)
		{
			return RandImpl::Get().RandInt(mi, mx);
		}
		float Rand::RandFloat(float mi, float mx)
		{
			if (mi >= mx)std::swap(mi, mx);
			int num = (int)(mx - mi);
			float f = RandInt(0, num + 1) + RandInt(0, RAND_MAX)*resmax;
			return f;
		}
		double Rand::RandDouble(double mi, double mx)
		{
			if (mi >= mx)std::swap(mi, mx);
			int num = (int)(mx - mi);
			double f = RandInt(0, num + 1) + RandInt(0, RAND_MAX)*resmaxd;
			return f;
		}
		float Rand::RandAround(float base, float percentage)
		{
			percentage = percentage > 1.0f ? 1.0f : (percentage < -1.0f ? -1.0f : percentage);
			return base*(1.0f + RandFloat(-percentage, percentage));
		}

		double  Rand::RandAround(double base, double percentage)
		{
			percentage = percentage > 1.0 ? 1.0 : (percentage < -1.0 ? -1.0 : percentage);
			return base*(1.0 + RandDouble(-percentage, percentage));
		}
		BaseString Rand::RandNumString()
		{
			//
			// 第一步,手动将正则表达式翻译成序列生成器的调用
			// 第二部,编写算法自动将正则表达式翻译成序列生成器的调用
			static NumGeneratorImpl num_generator;
			return num_generator.Build().c_str();
		}
		BaseString Rand::RandString(int minLength, int maxLength, DWORD flag )
		{
			BaseString out;
			RandImpl::Get().RandString(out, minLength, maxLength, flag);
			return out;
		}
		void Rand::RandString(BaseString& out, int minLength, int maxLength, DWORD flag)
		{
			RandImpl::Get().RandString(out, minLength, maxLength, flag);
		}


		RandNumGenerator::RandNumGenerator() :m_impl(new NumGeneratorImpl()){}
		RandNumGenerator::~RandNumGenerator()
		{
			if (m_impl)delete m_impl;
		}
		void RandNumGenerator::SetIntPartCount(unsigned int count)
		{
			m_impl->SetIntPartCount(count);
		}
		void RandNumGenerator::SetDigitPartCount(unsigned int count)
		{
			m_impl->SetDigitPartCount(count);
		}
		void RandNumGenerator::SetExpPartCount(unsigned int count)
		{
			m_impl->SetExpPartCount(count);
		}
		std::string RandNumGenerator::Generate()
		{
			return m_impl->Build();
		}
	}
}
